package com.itaming.lycheeframework.support.utils;

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import lombok.experimental.UtilityClass;
import org.springframework.util.Assert;

import java.lang.reflect.Type;

/**
 * Type工具类
 *
 * @author A.Ming
 */
@UtilityClass
public class TypeUtil {

    /**
     * 参数化方式构造类型
     * <p>
     * 如：构造<code>List&lt;Set&lt;Integer&gt;&gt;</code>类型，
     * 可将类型按顺序传入：<code>List.class, Set.class, Integer.class</code>
     *
     * @param classes 类型数组
     * @return Type
     */
    public static Type constructParametricType(Class<?>... classes) {
        return constructParametricType(getObjectMapper().getTypeFactory(), classes);
    }

    /**
     * 参数化方式构造类型
     * <p>
     * 如：构造<code>List&lt;Set&lt;Integer&gt;&gt;</code>类型，
     * 可将类型按顺序传入：<code>List.class, Set.class, Integer.class</code>
     *
     * @param typeFactory TypeFactory
     * @param classes     类型数组
     * @return Type
     */
    public static Type constructParametricType(TypeFactory typeFactory, Class<?>... classes) {
        Assert.isTrue(classes.length > 0, "Classes must not be empty");

        if (classes.length == 1) {
            return classes[0];
        }

        JavaType javaType = typeFactory.constructParametricType(classes[classes.length - 2], classes[classes.length - 1]);
        for (int i = classes.length - 3; i >= 0; i--) {
            javaType = typeFactory.constructParametricType(classes[i], javaType);
        }

        return javaType;
    }

    /**
     * 获取ObjectMapper
     *
     * @return ObjectMapper
     */
    private static ObjectMapper getObjectMapper() {
        try {
            return SpringUtil.getBean(ObjectMapper.class);
        } catch (Exception e) {
            return new ObjectMapper();
        }
    }

}
